package com.vhly.tuite.twclient.client;

import android.content.SharedPreferences;
import com.vhly.tuite.twclient.model.Status;
import com.vhly.tuite.twclient.util.StreamUtil;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Vector;
import java.util.zip.GZIPInputStream;
import java.util.zip.ZipInputStream;

/**
 * Created by IntelliJ IDEA.
 * User: vhly[FR]
 * Date: 2010-3-3
 * Time: 14:59:47
 */
public final class TwitterClient {

    public static final String twServer = "http://vhlyserver.appspot.com/tw";

    private String account;
    private String password;

    private String screen_name;

    private byte[] authData;

    private boolean processing;

    private static TwitterClient outInstance;

    public static TwitterClient getInstance() {
        if (outInstance == null) {
            outInstance = new TwitterClient();
        }
        return outInstance;
    }

    public void init(String acc, String pwd) {
        this.account = acc;
        this.password = pwd;
        authData = genAuthData(acc, pwd);
        processing = false;
    }

    public void setAccountInfo(String name, String pass) {
        account = name;
        password = pass;
        authData = genAuthData(name, pass);
    }

    // 

    public String doDirectMessage(String since) {
        String xml = null;
        TwRequest req = new TwRequest(Constants.CATEGORY_DIRECT_MESSAGES, Constants.METHOD_DIRECT_MESSAGES, Constants.HTTP_API_GET, Constants.FORMAT_TYPE_XML);
        req.setAuthType(Constants.AUTH_TYPE_BASIC);
        req.setAuthData(authData);
        if (since != null && since.length() > 0) {
            req.putParameter("since", since);
        }
        TwResponse resp = invokeTW(req);
        if (resp != null) {
            xml = processResponseData(resp);
        }
        resp = null;
        req = null;
        return xml;
    }

    public String doRateLimitStatus(boolean bAuth) {
        String xml = null;
        TwRequest req = new TwRequest(Constants.CATEGORY_ACCOUNT, Constants.METHOD_ACCOUNT_RATE_LIMIT_STATUS, Constants.HTTP_API_GET, Constants.FORMAT_TYPE_XML);
        if (bAuth) {
            req.setAuthType(Constants.AUTH_TYPE_BASIC);
            req.setAuthData(authData);
        }
        TwResponse resp = invokeTW(req);
        if (resp != null) {
            xml = processResponseData(resp);
        }
        resp = null;
        req = null;
        return xml;
    }

    public String doFriendsIDS() {
        String xml = null;
        TwRequest req = new TwRequest(Constants.CATEGORY_SOCIAL_GRAPH, Constants.METHOD_FRIENDS, Constants.HTTP_API_GET, Constants.FORMAT_TYPE_XML);
        req.setAuthType(Constants.AUTH_TYPE_BASIC);
        req.setAuthData(authData);
        TwResponse resp = invokeTW(req);
        if (resp != null) {
            xml = processResponseData(resp);
        }
        resp = null;
        req = null;
        return xml;
    }

    public String doStatusesPublicTimeLine() {
        String xml = null;
        TwRequest req = new TwRequest(Constants.CATEGORY_STATUS, Constants.METHOD_STATUSES_PUBLIC_TIMELINE, Constants.HTTP_API_GET, Constants.FORMAT_TYPE_XML);
        req.setAuthType(Constants.AUTH_TYPE_NONE);
        TwResponse resp = invokeTW(req);
        if (resp != null) {
            xml = processResponseData(resp);
        }
        resp = null;
        req = null;
        return xml;
    }

    public String doStatusesFollowers() {
        String xml = null;
        TwRequest req = new TwRequest(Constants.CATEGORY_STATUS, Constants.METHOD_STATUSES_FOLLOWERS, Constants.HTTP_API_GET, Constants.FORMAT_TYPE_XML);
        req.setAuthType(Constants.AUTH_TYPE_BASIC);
        req.setAuthData(authData);
        TwResponse resp = invokeTW(req);
        if (resp != null) {
            xml = processResponseData(resp);
        }
        resp = null;
        req = null;
        return xml;
    }

    public String doStatusesFriends() {
        String xml = null;
        TwRequest req = new TwRequest(Constants.CATEGORY_STATUS, Constants.METHOD_STATUSES_FRIENDS, Constants.HTTP_API_GET, Constants.FORMAT_TYPE_XML);
        req.setAuthType(Constants.AUTH_TYPE_BASIC);
        req.setAuthData(authData);
        TwResponse resp = invokeTW(req);
        if (resp != null) {
            xml = processResponseData(resp);
        }
        resp = null;
        req = null;
        return xml;
    }

    public Vector<Status> doStatusesFriendsTimeLine(String since) {
        String xml;
        TwRequest req = new TwRequest(Constants.CATEGORY_STATUS, Constants.METHOD_STATUSES_FRIENDS_TIMELINE, Constants.HTTP_API_GET, Constants.FORMAT_TYPE_XML);
        req.setAuthType(Constants.AUTH_TYPE_BASIC);
        req.setAuthData(authData);
        if (since != null) {
            req.putParameter("since", since);
        }
        TwResponse resp = invokeTW(req);
        Vector<Status> ret = null;
        if (resp != null) {
            xml = processResponseData(resp);
            if (xml != null) {
                ret = TwitterParser.parseTweets(xml);
                xml = null;
            }
        }
        resp = null;
        req = null;
        return ret;
    }

    public TwRequest makeStatusesHomeTimeLineReq(String since) {
        TwRequest req = new TwRequest(Constants.CATEGORY_STATUS, Constants.METHOD_STATUSES_HOME_TIMELINE, Constants.HTTP_API_GET, Constants.FORMAT_TYPE_XML);
        req.setAuthType(Constants.AUTH_TYPE_BASIC);
        req.setAuthData(authData);
        if (since != null) {
            req.putParameter("since", since);
        }
        return req;
    }

    /**
     * 
     * @param status
     * @return TwRequest
     */
    public TwRequest makeStatusesUpdate(String status) {
        TwRequest req = null;
        if (status != null) {
            req = new TwRequest(Constants.CATEGORY_STATUS, Constants.METHOD_STATUSES_UPDATE, Constants.HTTP_API_POST, Constants.FORMAT_TYPE_XML);
            req.setAuthType(Constants.AUTH_TYPE_BASIC);
            req.setAuthData(authData);
            req.putParameter("status", status);
        }
        return req;
    }

    public Vector<Status> doStatusesHomeTimeLine(String since) {
        String xml;
        TwRequest req = new TwRequest(Constants.CATEGORY_STATUS, Constants.METHOD_STATUSES_HOME_TIMELINE, Constants.HTTP_API_GET, Constants.FORMAT_TYPE_XML);
        req.setAuthType(Constants.AUTH_TYPE_BASIC);
        req.setAuthData(authData);
        if (since != null) {
            req.putParameter("since", since);
        }
        TwResponse resp = invokeTW(req);
        Vector<Status> ret = null;
        if (resp != null) {
            xml = processResponseData(resp);
            if (xml != null) {
                ret = TwitterParser.parseTweets(xml);
                xml = null;
            }
        }
        resp = null;
        req = null;
        return ret;
    }

    public String doStatusesUserTimeLine(String id, String since_id) {
        String xml = null;
        TwRequest req = new TwRequest(Constants.CATEGORY_STATUS, Constants.METHOD_STATUSES_USER_TIMELINE, Constants.HTTP_API_GET, Constants.FORMAT_TYPE_XML);
        if (id != null && id.length() > 0) {
            req.setHasId(true);
            req.putParameter("tt_id", id);
        }
        if (since_id != null && since_id.length() > 0) {
            req.putParameter("since_id", since_id);
        }
//        req.setAuthType(Constants.AUTH_TYPE_BASIC);
//        req.setAuthData(authData);
        TwResponse resp = invokeTW(req);
        if (resp != null) {
            xml = processResponseData(resp);
        }
        resp = null;
        req = null;
        return xml;
    }

    public String doStatusesUpdate(String status) {
        String xml = null;
        TwRequest req = new TwRequest(Constants.CATEGORY_STATUS, Constants.METHOD_STATUSES_UPDATE, Constants.HTTP_API_POST, Constants.FORMAT_TYPE_XML);
        req.setAuthType(Constants.AUTH_TYPE_BASIC);
        req.setAuthData(authData);
        req.putParameter("status", status);
        TwResponse resp = invokeTW(req);
        if (resp != null) {
            xml = processResponseData(resp);
        }
        resp = null;
        req = null;
        return xml;
    }

    public static TwResponse invokeTW(TwRequest request) {
        TwResponse response = null;
        if (request != null) {
            byte[] buf = request.genRequestData();
            URL url = null;
            HttpURLConnection http = null;
            if (buf != null) {
                try {
                    url = new URL(twServer);
//                    http = (HttpConnection) Connector.open(twServer, Connector.READ_WRITE, true);
                    http = (HttpURLConnection) url.openConnection();
                    http.setUseCaches(false);
                    http.setFollowRedirects(false);
                    http.setDoOutput(true);
                    http.setDoInput(true);
                    http.setRequestMethod("POST");
                    http.setRequestProperty("Accept-Encoding", "gzip");
                    http.setRequestProperty("User-Agent", "TuiTe/1.0(gzip)");
                    http.setRequestProperty("x-ce", "gzip");
                    http.setRequestProperty("Content-Length", Integer.toString(buf.length));
//                    OutputStream out = http.openOutputStream();  // J2ME
                    OutputStream out = http.getOutputStream();
                    out.write(buf);
                    response = new TwResponse();
                    response.state = http.getResponseCode();
//                    System.out.println("response.state = " + response.state);
                    response.message = http.getResponseMessage();
//                    if (response.state == 200) {
                    int len = (int) http.getContentLength();
//                        if (len > 0) {
//                    InputStream in = http.openInputStream();  // J2ME
                    InputStream in = http.getInputStream();
                    response.data = StreamUtil.readInput(in);
                    in.close();
//                        }
//                    } else {
//                        System.out.println("response message = " + response.message);
//                    }
//                    String enc = http.getEncoding();
                    String enc = http.getContentEncoding();
                    if (enc == null) {
                        enc = http.getHeaderField("x-ce");
                    }
                    if (enc != null) {
                        response.contentencoding = enc;
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    StreamUtil.close(http);
                }
            }
        }
        return response;
    }

    public static String processResponseData(TwResponse response) {
        String ret = null;
        if (response != null) {
            if (response.state == 200) {
                byte[] data = response.data;
                if (data != null) {
                    String enc = response.contentencoding;
//                    System.out.println("enc = " + enc);
                    if (enc != null) {
                        if (enc.equals("gzip")) {
                            ByteArrayInputStream bin = null;
                            GZIPInputStream gzip = null;
                            try {
                                bin = new ByteArrayInputStream(data);
                                gzip = new GZIPInputStream(bin);
                                data = StreamUtil.readInput(gzip);
                            } catch (Exception ioe) {
                                ioe.printStackTrace();
                                data = null;
                            } finally {
                                StreamUtil.close(gzip);
                                StreamUtil.close(bin);
                            }
                        }
                    }
                    if (data != null) {
                        try {
                            ret = new String(data, "UTF-8");
//                            System.out.println("ret = " + ret);
                        } catch (UnsupportedEncodingException e) {
                            ret = new String(data);
                        }
                    }
                }
            }
        }
        return ret;
    }

    public static byte[] genAuthData(String name, String pass) {
        byte[] buf = null;
        if (name != null && pass != null) {
            ByteArrayOutputStream bout = new ByteArrayOutputStream();
            try {
                byte[] buf1 = null;
                try {
                    buf1 = name.getBytes("UTF-8");
                } catch (UnsupportedEncodingException e) {
                    buf1 = name.getBytes();
                }
                bout.write(buf1);
                bout.write(':');
                try {
                    buf1 = pass.getBytes("UTF-8");
                } catch (UnsupportedEncodingException e) {
                    buf1 = pass.getBytes();
                }
                bout.write(buf1);
                buf1 = bout.toByteArray();
                int len = buf1.length;
                for (int i = len - 1; i >= 0; i--) {
                    buf1[i] ^= i;
                }
                buf = buf1;
            } catch (IOException ioe) {
                ioe.printStackTrace();
            }
        }
        return buf;
    }
}
